﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Xml;

using vJine.Core.IoC;
using vJine.Core.ORM;

namespace vJine.Core.IO.Xml {
    public partial class XmlHelper {

        static MethodInfo tostringObject =
            new Exec<XmlHelper, XmlDocument, XmlNode>(ToString<XmlHelper>).Method.GetGenericMethodDefinition();
        static void ToString<T>(T xmlObject, XmlDocument xmlDoc, XmlNode xmlNode) where T : class, new() {
            Class<T>.Property[] P = Class<T>.GetMap();
            for (int i = 0, len = P.Length; i < len; i++) {
                Class<T>.Property p_i = P[i];
                if (p_i.IsXmlIgnore) {
                    continue;
                }

                if (p_i.IsPrimitive || p_i.pType == Reflect.@type) {
                    object objValue = p_i.Get(xmlObject);
                    if (objValue == null) {
                        continue;
                    }
                    string xmlValue =
                        p_i.pType == Reflect.@type ? Reflect.GetTypeName(objValue as Type) : objValue.ToString();

                    if (p_i.IsXmlAttribute) {
                        XmlAttribute xa = xmlDoc.CreateAttribute(p_i.Name);
                        xa.Value = xmlValue ;
                        xmlNode.Attributes.Append(xa);
                    } else {
                        XmlNode subnode = xmlDoc.CreateElement(p_i.Name);
                        subnode.InnerText = xmlValue;
                        xmlNode.AppendChild(subnode);
                    }
                } else if (p_i.pType == Reflect.byteArray) {
                    byte[] objValue = p_i.Get(xmlObject) as byte[];
                    if (objValue == null) {
                        continue;
                    }

                    XmlElement xml_bytes = xmlDoc.CreateElement(p_i.Name);
                    xml_bytes.InnerText = Convert.ToBase64String(objValue);
                    xmlNode.AppendChild(xml_bytes);
                } else {
                    object objValue = p_i.Get(xmlObject);
                    if (objValue == null) {
                        continue;
                    }

                    XmlElement xml_obj = xmlDoc.CreateElement(p_i.Name);

                    tostringObject
                        .MakeGenericMethod(p_i.pType)
                        .Invoke(null, new object[] { objValue, xmlDoc, xml_obj });

                    xmlNode.AppendChild(xml_obj);
                }
            }

            if (Reflect.IsList(xmlObject)) {
                tostringList
                    .MakeGenericMethod(Reflect.GetGenericArgs<T>())
                    .Invoke(null, new object[] { xmlObject, xmlDoc, xmlNode });
            } else if (Reflect.IsDictionary(xmlObject)) {
                tostringDict
                    .MakeGenericMethod(Reflect.GetGenericArgs<T>())
                    .Invoke(null, new object[] { xmlObject, xmlDoc, xmlNode });
            }
        }

        static MethodInfo tostringList =
            new Exec<IList<XmlHelper>, XmlDocument, XmlNode>(ToString<XmlHelper>).Method.GetGenericMethodDefinition();
        static void ToString<T>(IList<T> xmlObject, XmlDocument xmlDoc, XmlNode xmlNode) where T : class, new() {
            string Name = typeof(T).Name;
            for (int i = 0, len = xmlObject.Count; i < len; i++) {
                T obj_i = xmlObject[i];
                if (obj_i == null) {
                    continue;
                }

                XmlNode xmlSubNode = xmlDoc.CreateElement(Name);

                ToString<T>(obj_i, xmlDoc, xmlSubNode);

                xmlNode.AppendChild(xmlSubNode);
            }
        }

        static MethodInfo tostringDict =
            new Exec<IDictionary<string, XmlHelper>, XmlDocument, XmlNode>(ToString<string, XmlHelper>).Method.GetGenericMethodDefinition();
        static void ToString<K, V>(IDictionary<K, V> xmlObject, XmlDocument xmlDoc, XmlNode xmlNode) where V : class, new() {

            string nodeName = Class<V>.Name;
            //TODO:Key校验
            foreach (KeyValuePair<K, V> oEntry in xmlObject) {
                V obj_i = oEntry.Value;
                if (obj_i == null) {
                    continue;
                }

                XmlNode xmlSubNode = xmlDoc.CreateElement(nodeName);

                ToString<V>(obj_i, xmlDoc, xmlSubNode);

                xmlNode.AppendChild(xmlSubNode);
            }
        }
    }
}
